package com.bluebench.bigul.service.resolver;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import com.bluebench.bigul.domain.Element;
import com.bluebench.bigul.domain.Element.Attribute;
import com.bluebench.bigul.domain.Element.Parameter;
import com.bluebench.bigul.domain.Invocation;
import com.bluebench.bigul.domain.Tag;
import com.bluebench.bigul.exception.GraphicInitializationException;

public class PrimitiveExpressionResolver extends DefaultExpressionResolver{

	Object value;
	
	void setValue(Object o){
		value = o;
	}
	
		
	@Override
	public void resolve() throws GraphicInitializationException {
		
		switch(tag.getElementType()){
		case ELEMENT:
			Element element = ((Element)tag);
			List<Element> elementList = element.getElements();
			if(elementList!=null){
				resolveElements(elementList);
			}
			List<Attribute> attributeList= element.getAttributes();
			if(attributeList!=null){
				resolveAttributes(attributeList);
			}			
			Invocation invocation = element.getInvocation();
			if(invocation!=null){
				List<Parameter> constructorParams = invocation.getParameters();
				resolveParameter(constructorParams);				
			}
			break;
		case ATTRIBUTE:
			Attribute attribute = (Attribute)tag;
			List<Parameter> parameterList = attribute.getParameters();
			if(parameterList!=null && (!parameterList.isEmpty())){
				resolveParameter(parameterList);
			}
			break;
		case PARAMETER:
			Parameter p = (Parameter)tag;
			if(p.isNested()){
				Element e = (Element)p.getValue();
				e.setResolver(getInstance(PRIMITIVE_RESOLVER));
				e.resolve();
			}else if(p.isCollection()){
				List<Element.Parameter> collection = (ArrayList<Element.Parameter>)p.getValue();
				for(Element.Parameter param : collection){
					resolvePrimitive(param);
				}				
			}else{
				resolvePrimitive(tag);
			}
			break;
		}		
		
	}
	
	protected void resolvePrimitive(Tag t) throws GraphicInitializationException{
		Parameter p = (Parameter)t;
		String type = p.getType();
		Object value = p.getValue();
		if(value instanceof Element){
			Element e = (Element)value;
			e.setResolver(getInstance(PRIMITIVE_RESOLVER));
			e.resolve();
		}else{
			if(validate(type)){
				setParameterValue(p,value);
			}
		}
	}
	
	
	
	
	/**
	 * Primitive values can be assigned in two ways in the xml 1) Explicity 2) Implicitly
	 * 
	 * Explicity means direct Assignment for example
	 * 	 <param id="red" name="red" type="_float" value="110"/>
	 * You can see 110 is explicitly assigned as a value. 
	 * 
	 * Whereas for Implicit assignment the value is indirectly assigned using another constant as follows
	 * 	<base-color id="bcblue" value="color.BLUE" type="color"/>
	 * 
	 * You can see the value is assigned as color.BLUE which actually refers to com.itextpdf.text.BaseColor.BLUE 
	 * i.e. a constant by the name BLUE in the class com.itextpdf.text.BaseColor. This kind of primitive assignment 
	 * SHOULD also be taken care by this method.
	 * 
	 * @param t
	 */
	/*protected void resolvePrimitive(Tag t){
		Parameter p = (Parameter)t;
		String type = p.getType();
		Object o = p.getValue();
		Object resolvedVal =null;
		
		resolvedVal = o;
		
		
		
		 * Commenting this section because PrimitiveExpressionResolver must only deal with resolving primitives and not elements.\
		 * This specific piece of code was written before the GlobalExpressionResolvers and DefaultExpressionResolvers were created, 
		 * In such a case this piece of code was actually resolving the primitive data in param values that were referenced.
		 * 
		 * Now since we have the mentioned classes all the primitive resolving for global and default in done by the respective classes
		 * and the template always receives resolved default and global data
		 * 
		 
		if(o instanceof Element){
			Element e = (Element)o;
			if(e.getField()!=null){
				resolvedVal = ReflectionUtil.getFieldValueFromElement(e).toString();
			}
		}else{
			resolvedVal = o;
		}
		
		
		 * The resolved value must be of primitive type and not an Element
		 
		if(!(o instanceof Element)){
			if(validate(type)){
				setParameterValue(p,resolvedVal);
			}
		}
		
	}*/
	@Override
	public boolean validate(String type){
		if(type!=null && type.startsWith("_")){
			return true;
		}else{
			return false;
		}
	}
	
	
	private void resolveElements(List<Element> elementList) throws GraphicInitializationException{
		for(Element e : elementList){
			e.setResolver(getInstance(PRIMITIVE_RESOLVER));
			e.resolve();
		}
	}
	
	private void resolveAttributes(List<Attribute> attributeList) throws GraphicInitializationException{
		for(Attribute a : attributeList){
			a.setResolver(getInstance(PRIMITIVE_RESOLVER));
			a.resolve();
		}
	}
	
	private void resolveParameter(List<Parameter> parameterList) throws GraphicInitializationException{
		for(Parameter p : parameterList){
			p.setResolver(getInstance(PRIMITIVE_RESOLVER));
			p.resolve();
		}
	}
	
	
	public static void setParameterValue(Parameter p,Object value){
		
		String type = p.getType().replace("_", "");
		
		if(type.equals("int")){
			
			p.setValue(Integer.parseInt(value.toString()));
			
		}else if(type.equals("float")){
			
			p.setValue(Float.parseFloat(value.toString()));
			
		}else if(type.equals("double")){
			
			p.setValue(Double.parseDouble(value.toString()));
			
		}else if(type.equals("char")){
			
			p.setValue(value.toString().charAt(0));			
			
		}else if(type.equals("long")){
			
			p.setValue(Long.parseLong(value.toString()));
			
		}else if(type.equals("byte")){
			
			p.setValue(Byte.parseByte(value.toString()));
			
		}else if(type.equals("boolean")){
			
			p.setValue(Boolean.parseBoolean(value.toString()));
			
		}else{
			//TODO : throw exception.
		}
	}

	public Tag getTag() {
		return tag;
	}
	
	
	


}
